/*
   Copyright (c) [2023] [魔凤啸天]
   [MFUI] is licensed under Mulan PSL v2.
   You can use this software according to the terms and conditions of the Mulan PSL v2. 
   You may obtain a copy of Mulan PSL v2 at:
            http://license.coscl.org.cn/MulanPSL2 
   THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.  
   See the Mulan PSL v2 for more details.  
*/
#include "canvas.hpp"

namespace MFUI{
	void Canvas::pointcallback(Canvas* c,SDL_FPoint* p){
		c->setcolor(c->defaultcolor);
		c->drawfpoint(*p);
	}
	Canvas::Canvas(Window* win,int w,int h):callback(pointcallback),alpha(255),
	w(w),h(h),build(false),painted(false),defaultcolor({255,255,255,255}){
		texture=win->createtexture(w,h,SDL_BLENDMODE_BLEND);
		imagecache=win->createtexture(w,h,SDL_BLENDMODE_BLEND);
		pixels=win->createimagebuffer(w,h);
	}
	Canvas::~Canvas(){
		SDL_DestroyTexture(texture);
		SDL_DestroyTexture(imagecache);
		free(pixels);
		for(auto v:commands)delete v;
	}
	void Canvas::drawfpoint(SDL_FPoint p){
		commands.emplace_back(new DrawFPoint(p));
	}
	void Canvas::drawpoint(SDL_Point p){
		commands.emplace_back(new DrawPoint(p));
	}
	void Canvas::drawfrect(SDL_FRect& r){
		commands.emplace_back(new DrawFRect(r));
	}
	void Canvas::drawrect(SDL_Rect& r){
		commands.emplace_back(new DrawRect(r));
	}
	void Canvas::fillfrect(SDL_FRect& r){
		commands.emplace_back(new FillFRect(r));
	}
	void Canvas::fillrect(SDL_Rect& r){
		commands.emplace_back(new FillRect(r));
	}
	void Canvas::setcolor(SDL_Color color){
		commands.emplace_back(new SetColor(color));
	}
	void Canvas::drawftexture(SDL_Texture* t,SDL_Rect& src,SDL_FRect& dst,Uint8 a){
		commands.emplace_back(new DrawFTexture(t,src,dst,a));
	}
	void Canvas::drawtexture(SDL_Texture* t,SDL_Rect& src,SDL_Rect& dst,Uint8 a){
		commands.emplace_back(new DrawTexture(t,src,dst,a));
	}
	void Canvas::drawftexturex(SDL_Texture* t,SDL_Rect& src,SDL_FRect& dst,
	SDL_RendererFlip f,double& degree,SDL_FPoint& center,Uint8 a){
		commands.emplace_back(new DrawFTextureEx(t,src,dst,f,degree,center,a));
	}
	void Canvas::drawtexturex(SDL_Texture* t,SDL_Rect& src,SDL_Rect& dst,
	SDL_RendererFlip f,double& degree,SDL_Point& center,Uint8 a){
		commands.emplace_back(new DrawTextureEx(t,src,dst,f,degree,center,a));
	}
	bool Canvas::confirmdraw(){return redraw|build;}
	void Canvas::draw(Renderer* r,bool updatecache){
		painted=false;
		if(redraw){
			redraw=false;
			_draw(r,updatecache);
			SDL_SetTextureAlphaMod(texture,alpha);
			r->settarget(texture);
			r->setdrawcolor({0,0,0,255});
			r->clear();
			r->copy(imagecache,nullptr,nullptr);
			if(build){
				build=false;
				if(clean){
					for(auto v:commands)v->draw(r),delete v;
					commands.clear();
				}
				else for(auto v:commands)v->draw(r);
				r->gettexturepixel(nullptr,pixels,w);
				r->settarget(imagecache);
				r->clear();
				r->copy(texture,nullptr,nullptr);
				r->setdefaulttarget();
				r->copyF(texture,nullptr,&rect);
				buildfinish();
				return;
			}
			for(auto v:commands)v->draw(r);
			r->setdefaulttarget();
			r->copyF(texture,nullptr,&rect);
			return;
		}
		build=false;
		r->settarget(texture);
		if(clean){
			for(auto v:commands)delete v;
			commands.clear();
		}
		r->gettexturepixel(nullptr,pixels,w);
		r->settarget(imagecache);
		r->setdrawcolor({0,0,0,255});
		r->clear();
		r->copy(texture,nullptr,nullptr);
		r->setdefaulttarget();
		buildfinish();
	}
	void* Canvas::getpixels()const{return pixels;}
	void Canvas::applychange(){
		redraw=true;
		painted=true;
		notifyparent();
	}
	void Canvas::applybuild(bool c){clean=c,build=true,notifyparent();}
	void Canvas::mousemove(Window* win,SDL_FPoint p){
		if(getstate()==state_pressed){
			p.x=(p.x-rect.x)/rect.w*w,p.y=(p.y-rect.y)/rect.h*h;
			callback(this,&p);
			applychange();
		}
	}
	SDL_FPoint Canvas::getcanvassize()const{return {w,h};}
	void Canvas::buildfinish(){}
	void Canvas::clear(){
		for(auto v:commands)delete v;
		commands.clear();
	}
}